package com.eva.core.utils;

import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * AES加解密
 * @author Eva.Caesar Liu
 * @date 2022/02/19 18:03
 */
@Data
@Component
public class AES {

    // 密钥
    @Value("${security.aes.key}")
    private String key;

    // 偏移量
    @Value("${security.aes.iv}")
    private String iv;

    // 密钥长度
    private Integer keyLen = 128;

    public AES() {
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 加密
     *
     * @date 2018年3月3日下午12:20:27
     * @return
     * @throws SecurityException
     */
    public String encrypt(String plainText) throws SecurityException {
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");// 创建密码器
            cipher.init(Cipher.ENCRYPT_MODE, this.getAESKey(), new IvParameterSpec(paddingIv(iv)));// 初始化
            return new Base64().encodeAsString(cipher.doFinal(plainText.getBytes("UTF-8")));
        } catch (Exception e) {
            throw new SecurityException("AES encrypt throw an exception", e);
        }
    }

    /**
     * 解密
     *
     * @date 2018年3月3日下午1:14:21
     * @param cipherText
     * @return
     * @throws SecurityException
     */
    public String decrypt(String cipherText) throws SecurityException {
        try {
            byte[] encrypted = new Base64().decode(cipherText);
            ;
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            cipher.init(Cipher.DECRYPT_MODE, this.getAESKey(), new IvParameterSpec(paddingIv(iv)));
            return new String(cipher.doFinal(encrypted), "UTF-8");
        } catch (Exception e) {
            throw new SecurityException("AES decrypt throw an exception", e);
        }
    }

    /**
     * 获取AES key
     *
     * @date 2018年3月4日下午8:49:27
     * @return
     * @throws Exception
     */
    private SecretKeySpec getAESKey() throws Exception {
        /* 使用原始密钥进行加密，要求密钥为密钥长度的倍数 */
        byte[] raw = key.getBytes("UTF-8");
        byte[] keyBytes = new byte[keyLen / 8];
        System.arraycopy(raw, 0, keyBytes, 0, raw.length);
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        return skeySpec;
    }

    /**
     * 初始化向量一直保持16位
     * @date 2018年3月5日下午9:30:35
     * @param iv
     * @return
     * @throws Exception
     */
    private byte[] paddingIv(String iv) throws Exception{
        byte[] ivBytes = iv.getBytes("UTF-8");
        byte[] bs = new byte[keyLen / 8];
        System.arraycopy(ivBytes, 0, bs, 0, ivBytes.length);
        return bs;
    }
}
